#include "MainWnd.h"
#include "ui_MainWnd.h"

#include "MainApp.h"
#include "MsgWnd.h"

#include "GlobalSignal.h"

#include <QDebug>
#include <QTimer>

#include "TestRecordManager.h"
#include "SNRecordManager.h"
#include "AppModel.h"

#include "NrfjprogCMDMgr.h"

MainWnd::MainWnd(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWnd)
  , enable_control_power_(false)
  , write_only_write_(true)
{
    qRegisterMetaType<zl::EUserConfirmType>("zl::EUserConfirmType");

    ui->setupUi(this);

    QObject::connect(GlobalSignal::getInstance(), &GlobalSignal::switchLanguage, this, &MainWnd::lang_change);

    QObject::connect(GlobalSignal::getInstance(), &GlobalSignal::wait_timeout, this, &MainWnd::event_wait_timeout);

    QObject::connect(GlobalSignal::getInstance(), &GlobalSignal::submit_new_sn, this, &MainWnd::event_submit_new_sn);

    QObject::connect(GlobalSignal::getInstance(), &GlobalSignal::confirm_type, this, &MainWnd::event_confirm_type);

    resetRecord();
}

MainWnd::~MainWnd()
{
    QObject::disconnect(GlobalSignal::getInstance(), &GlobalSignal::switchLanguage, this, &MainWnd::lang_change);

    QObject::disconnect(GlobalSignal::getInstance(), &GlobalSignal::wait_timeout, this, &MainWnd::event_wait_timeout);

    QObject::disconnect(GlobalSignal::getInstance(), &GlobalSignal::submit_new_sn, this, &MainWnd::event_submit_new_sn);

    QObject::disconnect(GlobalSignal::getInstance(), &GlobalSignal::confirm_type, this, &MainWnd::event_confirm_type);

    delete ui;
}

void MainWnd::lang_change()
{
    if (ui) ui->retranslateUi(this);

    setVersionInfo(APPMODEL()->Version());
}

void MainWnd::event_wait_timeout()
{
    auto_save_record(zl::ESNWT_ResultType_Failed);

    MsgWnd::ShowNormalInfo(tr("Wait power reset timeout"));
}

void MainWnd::event_submit_new_sn(QString info)
{
    if (info.isEmpty())
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Write sn step"), tr("is canceled"));
        return;
    }
    else if (info.size() != APPMODEL()->Config().sn_config.sn_rule_len)
    {
        qDebug() << "[ERROR]" << "user submit sn illegal";

        MsgWnd::ScanInputNewSN(tr("Input SN illegal"), tr("Scan input SN again"), "", this);
        return;
    }
    else
    {
        auto ret = SNRecordManager::getInstance()->SearchSNRecord(info);

        if (ret == EResult_Success)
        {
            MsgWnd::ScanInputNewSN(tr("Input SN is already used"), tr("Scan input SN again"), "", this);
            return;
        }
    }

    addSNTail(info);

    MsgWnd::ShowNormalInfo(tr("New SN is writing"), tr("please wait"));

    bool result = writeSN(info);

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Write new SN failed"));
        return;
    }

    QString sn_data;

    result = readSN(sn_data);

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Read current SN failed"));
    }
    else
    {
        record_.sn_info = sn_data;

        if (info.compare(sn_data) !=0)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);
            MsgWnd::ShowNormalInfo(tr("Write new SN error"), tr("SN in memory"), tr("is not equal to scaned before"));
        }
        else
        {
            auto_save_record();

            SNInfo sn;
            SNRecordManager::getInstance()->GetEmptySNData(sn);

            sn.account = record_.account;
            sn.name = record_.name;

            sn.sn_total = sn_data;
            sn.sn_tail = sn_data.right(SN_ADD_TAIL_LEN);
            sn.sn_info = sn_data.chopped(SN_ADD_TAIL_LEN);

            SNRecordManager::getInstance()->SaveSNRecord(sn);

            MsgWnd::ShowNormalInfo(tr("Write new SN success"));
        }
    }
}

void MainWnd::event_confirm_type(zl::EUserConfirmType type, bool confirm)
{  
    if (type == EUserConfirmType_EraseExistSN)
    {
        if (!confirm)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);
        }
        else
        {
            if (record_.action_type == ESNWT_ActionType_Erase)
                eraseOldSN();
            else if (record_.action_type == ESNWT_ActionType_OneKeyWrite)
                eraseOldSNWriteNewSN();
        }
    }
}

void MainWnd::SetConfigInfo(const QString& version, bool powerControl)
{
    enable_control_power_ = powerControl;

    setVersionInfo(version);
}

void MainWnd::setVersionInfo(const QString& version)
{
    QString version_ = QString("Ver:%1").arg(version);

    ui->lb_version->setText(version_);
}

bool MainWnd::eraseMcu()
{
    auto mgr = NrfjprogCMDMgr::getInstance();
    if (mgr == Q_NULLPTR)
    {
        qDebug() << "[ERROR]" << "erase mcu error, nrfjprog manager object is null";
        return false;
    }

    int32_t ret = mgr->NrfjprogEraseMcu();

    if (ENCMD_Result_Success != ret)
    {
        qDebug() << "[ERROR]" << "erase mcu error, erase mcu cmd ret failed";
        return false;
    }
    else
        qDebug() << "[INFO]" << "erase muc successed";

    return true;
}

bool MainWnd::sendResetSwitchPowerCmd()
{
    auto app = MainApp::Instance();
    if (!app)
    {
        qDebug() << "[ERROR]" << "send reset switch power cmd error, app is null";
        return false;
    }

    CSerialCommandWrapper* obj = app->GetSerialConnectObj();
    if (!obj)
    {
        qDebug() << "[ERROR]" << "send reset switch power cmd error, serial connect obj is null";
        return false;
    }

    int32_t ret = obj->ResetSwitchPowerCommand(zl::zlmodules::ST_CN15, 1);
    if (ret != 0)
    {
        qDebug() << "[ERROR]" << "send reset switch power cmd failed,ret: " << ret;
        return false;
    }
    else
        qDebug() << "[INFO]" << "send reset power cmd successed";

    return true;
}

void MainWnd::resetSwitchPowerResult(QByteArray& data)
{
    const int32_t msg_len = SWITCH_POW_RESET_INFO_LEN;

    if (data.size() != msg_len)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        qDebug() << "[ERROR]" << "receive reset switch power result error, data size: " << data.size() << " msg data: " << data.toHex();

        MsgWnd::ShowNormalInfo(tr("receive return msg"), tr("from reset power cmd error"));
        return;
    }

    char result = data.at(0);

    QString info(""), info1("");

    if (result == TURN_OFF_POW_FAILED)
    {
        info = tr("Reset switch power failed");
        info1 = tr("turn off power step fail");
    }
    else if (result == TURN_ON_POW_FAILED)
    {
        info = tr("Reset switch power failed");
        info1 = tr("turn on power step fail");
    }
    else if (result == RESET_POW_SUCCESS)
    {
        qDebug() << "[INFO]" << "receive reset switch power return info success";

        resetPowerSuccess();
        return;
    }
    else
    {
        qDebug() << "[ERROR]" << "receive reset switch power return info error, msg data: " << data.toHex();

        info = tr("Reset switch power failed");
        info1 = tr("receive ack msg error");
    }

    if (!info.isEmpty() && !info1.isEmpty())
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);
        MsgWnd::ShowNormalInfo(info, info1);
    }
}

void MainWnd::resetPowerSuccess()
{
    if (record_.action_type == ESNWT_ActionType_Mcu)
    {
        auto_save_record();

        QString info = tr("Erase mcu success");
        QString info1 = "";

        if (!enable_control_power_)
            info1 = tr("Please reset J-Link power maunally");

        MsgWnd::ShowNormalInfo(info, info1);
    }
    else if (record_.action_type == ESNWT_ActionType_Read)
    {
        resetPowerDoReadSN();
    }
    else if (record_.action_type == ESNWT_ActionType_Erase)
    {
        resetPowerDoEraseFlash();
    }
    else if (record_.action_type == ESNWT_ActionType_OneKeyWrite)
    {
        resetPowerDoOneKeyWrite();
    }
}

void MainWnd::resetPowerDoReadSN()
{
    QString sn_data;

    bool result = readSN(sn_data);

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Read current SN failed"));
    }
    else
    {
        record_.sn_info = sn_data;
        auto_save_record();

        MsgWnd::ShowNormalInfo(tr("Read current SN success"), tr("The SN is:%1").arg(sn_data));
    }
}

void MainWnd::resetPowerDoEraseFlash()
{
    QString sn_data;

    bool result = readSN(sn_data);

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Read current SN failed"));
    }
    else
    {
        if (!sn_data.isEmpty())
        {
            record_.sn_info = sn_data;

            qDebug() << "[INFO]" << "one key write sn, read old sn: " << sn_data;

            MsgWnd::ConfirmEraseExistSN(tr("Current SN is"), sn_data, tr("whethe erase the existed SN?"));
            return;
        }
        else
        {
            eraseOldSN();
        }
    }
}

void MainWnd::eraseOldSN()
{
    bool result = eraseSNMemory();

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Erase flash page failed"));
    }
    else
    {
        if (!record_.sn_info.isEmpty())
        {
            SNRecordManager::getInstance()->RemoveSNRecord(record_.sn_info.chopped(SN_ADD_TAIL_LEN));
        }

        auto_save_record();

        MsgWnd::ShowNormalInfo(tr("Erase flash page success"));
    }
}

void MainWnd::resetPowerDoOneKeyWrite()
{
    QString sn_data;

    bool result = readSN(sn_data);

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Read current SN failed"));
    }
    else
    {
        if (!sn_data.isEmpty())
        {
            qDebug() << "[INFO]" << "one key write sn, read old sn: " << sn_data;
            record_.sn_info = sn_data;

            MsgWnd::ConfirmEraseExistSN(tr("Current SN is"), sn_data, tr("whethe erase the existed SN?"));
            return;
        }
        else
        {
            eraseOldSNWriteNewSN();
        }
    }
}

void MainWnd::eraseOldSNWriteNewSN()
{
    if (!write_only_write_)
    {
        bool result = eraseSNMemory();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Erase flash page failed"));
            return;
        }
        else
        {
            qDebug() << "[INFO]" << "one key write sn, erase flash page success";
            if (!record_.sn_info.isEmpty())
            {
                SNRecordManager::getInstance()->RemoveSNRecord(record_.sn_info.chopped(SN_ADD_TAIL_LEN));
                record_.sn_info.clear();
            }

            MsgWnd::ScanInputNewSN(tr("Scan input new SN"), "", "", this);
            return;
        }
    }
    else
    {
        qDebug() << "[INFO]" << "one key write sn, jump erase flash page step";

        if (!record_.sn_info.isEmpty())
        {
            SNRecordManager::getInstance()->RemoveSNRecord(record_.sn_info.chopped(SN_ADD_TAIL_LEN));
            record_.sn_info.clear();
        }

        MsgWnd::ScanInputNewSN(tr("Scan input new SN"), "", "", this);
        return;
    }
}

bool MainWnd::eraseSNMemory()
{
    auto mgr = NrfjprogCMDMgr::getInstance();
    if (mgr == Q_NULLPTR)
    {
        qDebug() << "[ERROR]" << "erase flash page failed, nrfjprog manager object is null";
        return false;
    }

    auto ret = mgr->NrfjprogEraseSNMemory();

    if (ENCMD_Result_Success != ret)
    {
        qDebug() << "[ERROR]" << "erase flash page cmd ret failed";
        return false;
    }
    else
        qDebug() << "[INFO]" << "do erase flash page cmd successed";

    return true;
}

bool MainWnd::readSN(QString& data)
{
    data.clear();

    auto mgr = NrfjprogCMDMgr::getInstance();
    if (mgr == Q_NULLPTR)
    {
        qDebug() << "[ERROR]" << "read sn failed, nrfjprog manager object is null";
        return false;
    }

    auto ret = mgr->NrfjprogReadSNNum(data);

    if (ENCMD_Result_Success != ret)
    {
        qDebug() << "[ERROR]" << "read sn error, read sn cmd ret failed";
        return false;
    }
    else
        qDebug() << "[INFO]" << "do read sn cmd successed";

    return true;
}

void MainWnd::addSNTail(QString& data)
{
    data.append(":M");
}

bool MainWnd::writeSN(QString& data)
{
    QString sn = data.remove(DEL_STR_BLANK);

    if (sn.size() != (SN_MAX_LEN + SN_ADD_TAIL_LEN))
    {
        qDebug() << "[ERROR]" << "write sn failed, input sn error: " << data;
        return false;
    }

    auto mgr = NrfjprogCMDMgr::getInstance();
    if (mgr == Q_NULLPTR)
    {
        qDebug() << "[ERROR]" << "write sn failed, nrfjprog manager object is null";
        return false;
    }

    auto ret = mgr->NrfjprogWriteSNNum(sn);

    if (ENCMD_Result_Success != ret)
    {
        qDebug() << "[ERROR]" << "write sn error, write sn cmd ret failed";
        return false;
    }
    else
        qDebug() << "[INFO]" << "do write sn cmd successed";

    return true;
}

void MainWnd::SerialCommandResult(const unsigned char cmd, zl::zlmodules::CommandResultType type, QByteArray& data)
{
    QString info(""), info1("");

    if (type == zl::zlmodules::Crt_Success)
    {
        if (cmd == CMD_SWITCH_POWER_RESET)
        {
            qDebug() << "[INFO]" << "reset switch power success!";

            MsgWnd::ShowWaitInfo(tr("Send reset power cmd success"), tr("Please Wait"), "5");
            return;
        }
        else
        {
            info = tr("Monitor board ack error");
            info1 = tr("ack cmd error");
        }
    }
    else if (type == zl::zlmodules::Crt_Machine_busy)
    {
        info = tr("Monitor board is busy");
        info1 = tr("please retry after few seconds");
    }
    else
    {
        info = tr("Monitor ack reset power cmd");
        info1 = tr("cmd error: %1").arg(type);
    }

    if (!info.isEmpty() && !info1.isEmpty())
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);
        MsgWnd::ShowNormalInfo(info, info1);
    }
}

void MainWnd::SerialMsgInfo(const unsigned char cmd, QByteArray& data)
{
    qDebug() << "[INFO]" << "receive serial msg data: " << QByteArray(cmd, 1).toHex() << " msg data: " << data.toHex();

    emit GlobalSignal::getInstance()->close_msg_wnd();

    if (cmd == CMD_SWITCH_POWER_RESET)
    {
        resetSwitchPowerResult(data);
    }
    else
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        qDebug() << "[ERROR]" << "receive serial msg error, cmd error: " << QByteArray(cmd, 1).toHex() << " msg data: " << data.toHex();

        MsgWnd::ShowNormalInfo(tr("receive return msg"), tr("from reset power cmd error"));
        return;
    }
}

void MainWnd::resetRecord()
{
    TestRecordManager* instance = TestRecordManager::getInstance();

    if (instance == Q_NULLPTR)
    {
        qDebug() << "[ERROR]" << "reset record failed, test record mgr is null";
        MsgWnd::ShowNormalInfo(tr("Something error"));
        return;
    }

    instance->GetEmptyRecord(record_);
}

void MainWnd::on_btn_nor_erase_sn_clicked()
{
    record_.action_type = ESNWT_ActionType_Erase;

    if (!enable_control_power_)
    {
        resetPowerDoEraseFlash();
        return;
    }
    else
    {
        bool result = eraseMcu();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Erase MCU failed"));
            return;
        }

        result = sendResetSwitchPowerCmd();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Send cmd to reset power failed"));
            return;
        }
    }
}

void MainWnd::on_btn_nor_read_sn_clicked()
{
    record_.action_type = ESNWT_ActionType_Read;

    if (!enable_control_power_)
    {
        resetPowerDoReadSN();
        return;
    }
    else
    {
        bool result = eraseMcu();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Erase MCU failed"));
            return;
        }

        result = sendResetSwitchPowerCmd();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Send cmd to reset power failed"));
            return;
        }
    }
}

void MainWnd::on_btn_nor_erase_muc_clicked()
{
    record_.action_type = ESNWT_ActionType_Mcu;

    bool result = eraseMcu();

    if (!result)
    {
        auto_save_record(zl::ESNWT_ResultType_Failed);

        MsgWnd::ShowNormalInfo(tr("Erase MCU failed"));
        return;
    }

    if (!enable_control_power_)
    {
        resetPowerSuccess();
        return;
    }
    else
    {
        result = sendResetSwitchPowerCmd();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Send cmd to reset power failed"));
            return;
        }
    }
}

void MainWnd::on_btn_nor_one_key_write_clicked()
{
    record_.action_type = ESNWT_ActionType_OneKeyWrite;

    if (!enable_control_power_)
    {
        resetPowerDoOneKeyWrite();
        return;
    }
    else
    {
        bool result = eraseMcu();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Erase MCU failed"));
            return;
        }

        result = sendResetSwitchPowerCmd();

        if (!result)
        {
            auto_save_record(zl::ESNWT_ResultType_Failed);

            MsgWnd::ShowNormalInfo(tr("Send cmd to reset power failed"));
            return;
        }
    }

}

void MainWnd::auto_save_record(zl::ESNWT_ResultType type)
{
    record_.result_type = type;

    auto ret = TestRecordManager::getInstance()->SearchRecord(record_.record_id);
    if (ret == zl::EResult_Success)
    {
        qDebug() << "[ERROR]" << "action record saved";

        TestRecordManager::getInstance()->RemoveRecord(record_.record_id);
    }

    ret = TestRecordManager::getInstance()->SaveTestRecord(record_);

    if (ret != zl::EResult_Success)
    {
        qDebug() << "[ERROR]" << "auto save record fail, ret: " << ret;
    }

    resetRecord();
}

